// Copyright (c) 2005  INRIA Sophia-Antipolis (France).
// All rights reserved.
//
// This file is part of cgal-python; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public License as
// published by the Free Software Foundation; version 2.1 of the License.
// See the file LICENSE.LGPL distributed with cgal-python.
//
// Licensees holding a valid commercial license may use this file in
// accordance with the commercial license agreement provided with the software.
//
// This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
// WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
//
// $Id: Py_Delaunay_triangulation_3.cpp 167 2007-11-02 15:36:54Z spion $
// $URL: svn+ssh://scm.gforge.inria.fr/svn/cgal-python/trunk/cgal-python/bindings/Triangulations_3/Py_Delaunay_triangulation_3.cpp $
//
// Author(s)     : Naceur Meskini
//=========================================================================
// include ====================================================================
//#include <list>
#include <CGAL/basic.h>
#include <include/Kernels.h>
#include <CGAL/Delaunay_triangulation_3.h>
#include <CGAL/Triangulation_vertex_base_with_info_3.h>
#include <CGAL/Alpha_shape_vertex_base_3.h>
#include <CGAL/Alpha_shape_cell_base_3.h>

#include <boost/python.hpp>
#include <boost/cstdint.hpp>
#include <include/iterator.h>
#include <list>
#include "Py_Delaunay_triangulation_3_doc.h"

using namespace boost::python;
using boost::python::object;

template <class kernel,class Delaunay_triangulation,class Facet>
object dual(const Delaunay_triangulation& dt,const Facet& f)
{
	//three cases are possible:
	typedef typename kernel::Ray_3 			Ray_3;
	typedef typename kernel::Segment_3 		Segment_3;
	typedef typename kernel::Point_3 		Point_3;

	CGAL::Object o = dt.dual(f);

	Ray_3 r;
	Segment_3 s;
	Point_3 p;
	if( CGAL::assign(r,o) ) return object(r);
	else if(CGAL::assign(s,o)) return object(s);
	else {CGAL::assign(p,o);  return object(p);}	
	
}
template <class kernel,class Delaunay_triangulation,class Cell_handle>
object dual_2(const Delaunay_triangulation& dt,Cell_handle ch,int i)
{
	//three cases are possible:
	typedef typename kernel::Ray_3 			Ray_3;
	typedef typename kernel::Segment_3 		Segment_3;
	typedef typename kernel::Point_3 		Point_3;

	CGAL::Object o = dt.dual(ch,i);

	Ray_3 r;
	Segment_3 s;
	Point_3 p;
	if( CGAL::assign(r,o) ) return object(r);
	else if(CGAL::assign(s,o)) return object(s);
	else {CGAL::assign(p,o);  return object(p);}	
	
}
// insertion of list of points
template < class kernel,class Triangulation>
int py_insert(Triangulation& tr,boost::python::list pts)
{
	typedef typename kernel::Point_3 Point_3;
	int Nb_points = boost::python::extract<int>(pts.attr("__len__")());
	for(int i = 0 ; i < Nb_points ; i++)
	{
		Point_3 P = boost::python::extract<Point_3>(pts[i]); 
		tr.insert(P);
	}
	return Nb_points;
}

template <class Delaunay_triangulation_3,class Point_2,class Cell_handle>
boost::python::list py_vertices_in_conflict(const Delaunay_triangulation_3& dt,Point_2 pt,Cell_handle cell)
{
	boost::python::list result;
	typedef typename Delaunay_triangulation_3::Vertex_handle  Vertex_handle;
	std::list<Vertex_handle>  liste;
	dt.vertices_in_conflict(pt,cell,std::back_inserter(liste));
	typename std::list<Vertex_handle>::iterator iter;

	for(iter = liste.begin(); iter != liste.end(); iter++)
		result.append(*iter);
	
	return result;
}

template <class Delaunay_triangulation_3,class Point_2,class Cell_handle>
boost::python::tuple py_find_conflicts(const Delaunay_triangulation_3& dt,Point_2 pt,Cell_handle cell)
{
	boost::python::list result_facets;
	boost::python::list result_cells;

	typedef typename Delaunay_triangulation_3::Facet  Facet;

	std::list<Facet>  list_of_facets;
	std::list<Cell_handle>  list_of_cells;

	dt.find_conflicts(pt,cell,std::back_inserter(list_of_facets),std::back_inserter(list_of_cells));

	typename std::list<Facet>::iterator facet_iter;
	typename std::list<Cell_handle>::iterator cell_iter;

	for(facet_iter = list_of_facets.begin(); facet_iter != list_of_facets.end(); facet_iter++)
		result_facets.append(*facet_iter);
	for(cell_iter = list_of_cells.begin(); cell_iter != list_of_cells.end(); cell_iter++)
		result_cells.append(*cell_iter);
	
	return boost::python::make_tuple(result_facets,result_cells);
}
namespace  {

BOOST_PYTHON_MEMBER_FUNCTION_OVERLOADS(insert_overloads_1_2, insert, 1, 2)

BOOST_PYTHON_MEMBER_FUNCTION_OVERLOADS(side_of_sphere_overloads_2_3, side_of_sphere, 2, 3)

BOOST_PYTHON_MEMBER_FUNCTION_OVERLOADS(side_of_circle_overloads_2_3, side_of_circle, 2, 3)

BOOST_PYTHON_MEMBER_FUNCTION_OVERLOADS(side_of_circle_overloads_3_4, side_of_circle, 3, 4)

BOOST_PYTHON_MEMBER_FUNCTION_OVERLOADS(nearest_vertex_overloads_1_2, nearest_vertex, 1, 2)

BOOST_PYTHON_MEMBER_FUNCTION_OVERLOADS(is_valid_overloads_0_2, is_valid, 0, 2)

BOOST_PYTHON_MEMBER_FUNCTION_OVERLOADS(is_valid_overloads_1_3, is_valid, 1, 3)

}// namespace 

template < typename kernel>
void Py_Delaunay_triangulation_3()
{
	typedef CGAL::Alpha_shape_vertex_base_3<kernel>         Avb;
	typedef CGAL::Triangulation_vertex_base_with_info_3<boost::python::object,kernel,Avb> 	Vb;

	typedef CGAL::Alpha_shape_cell_base_3<kernel>           Fb;
	typedef CGAL::Triangulation_data_structure_3<Vb,Fb> 	Tds;

	typedef CGAL::Triangulation_3<kernel,Tds>   				Triangulation_3;
	typedef CGAL::Delaunay_triangulation_3<kernel,Tds>   		Delaunay_triangulation_3;

	typedef typename Triangulation_3::Facet 					Facet;
	typedef typename Triangulation_3::Finite_facets_iterator 	Finite_facets_iterator;
	typedef typename Triangulation_3::Facet_circulator			Facet_circulator;
	typedef typename Triangulation_3::All_facets_iterator 	    All_facets_iterator;
	typedef typename Triangulation_3::Cell_handle 				Cell_handle;
	typedef typename Triangulation_3::Cell_circulator 			Cell_circulator;
	typedef typename Triangulation_3::All_cells_iterator 		All_cells_iterator;
	typedef typename Triangulation_3::Finite_cells_iterator 	Finite_cells_iterator;

	typedef typename kernel::Point_3 							Point_3;
	typedef typename Triangulation_3::Point_iterator 			Point_iterator;

	typedef typename Triangulation_3::Vertex_handle 			Vertex_handle;
	typedef typename Triangulation_3::Finite_vertices_iterator 	Finite_vertices_iterator;
	typedef typename Triangulation_3::All_vertices_iterator 	All_vertices_iterator;

	typedef typename Triangulation_3::Edge 						Edge;
	typedef typename Triangulation_3::Finite_edges_iterator		Finite_edges_iterator;
	typedef typename Triangulation_3::All_edges_iterator		All_edges_iterator;

	typedef typename Triangulation_3::Locate_type 				Locate_type;
	typedef typename kernel::Segment_3 							Segment_3;
	typedef typename kernel::Triangle_3 						Triangle;


    class_< Delaunay_triangulation_3, bases< Triangulation_3 >  >("Delaunay_triangulation_3",Delaunay_triangulation_3_doc, init< optional< const kernel& > >())
        .def(init< const Delaunay_triangulation_3& >())
        .def("insert", (Vertex_handle (Delaunay_triangulation_3::*)(const Point_3&, Cell_handle) )&Delaunay_triangulation_3::insert, insert_overloads_1_2())
        .def("insert", (Vertex_handle (Delaunay_triangulation_3::*)(const Point_3&, Locate_type, Cell_handle, int, int) )&Delaunay_triangulation_3::insert)
        .def("insert", &py_insert<kernel,Delaunay_triangulation_3>,del_insert_doc)
        .def("move_point", &Delaunay_triangulation_3::move_point,move_point_doc)
        .def("remove", (bool(Delaunay_triangulation_3::*)(Vertex_handle))&Delaunay_triangulation_3::remove,remove_doc)
        .def("side_of_sphere", (CGAL::Bounded_side (Delaunay_triangulation_3::*)(const Cell_handle&, const Point_3&, bool) const)&Delaunay_triangulation_3::side_of_sphere, side_of_sphere_overloads_2_3(side_of_sphere_doc))
        .def("side_of_circle", (CGAL::Bounded_side (Delaunay_triangulation_3::*)(const Facet&, const Point_3&, bool) const)&Delaunay_triangulation_3::side_of_circle, side_of_circle_overloads_2_3(side_of_circle_doc))
        .def("side_of_circle", (CGAL::Bounded_side (Delaunay_triangulation_3::*)(const Cell_handle&, int, const Point_3&, bool) const)&Delaunay_triangulation_3::side_of_circle, side_of_circle_overloads_3_4())
        .def("nearest_vertex_in_cell", &Delaunay_triangulation_3::nearest_vertex_in_cell,nearest_vertex_in_cell_doc)
        .def("nearest_vertex", (Vertex_handle (Delaunay_triangulation_3::*)(const Point_3&, Cell_handle) const)&Delaunay_triangulation_3::nearest_vertex, nearest_vertex_overloads_1_2(nearest_vertex_doc))

        .def("is_Gabriel", (bool (Delaunay_triangulation_3::*)(Cell_handle, int) const)&Delaunay_triangulation_3::is_Gabriel,is_Gabriel_doc)
        .def("is_Gabriel", (bool (Delaunay_triangulation_3::*)(Cell_handle, int, int) const)&Delaunay_triangulation_3::is_Gabriel)
        .def("is_Gabriel", (bool (Delaunay_triangulation_3::*)(const Facet&) const)&Delaunay_triangulation_3::is_Gabriel)
        .def("is_Gabriel", (bool (Delaunay_triangulation_3::*)(const Edge&) const)&Delaunay_triangulation_3::is_Gabriel)
        .def("dual", (Point_3 (Delaunay_triangulation_3::*)(Cell_handle) const)&Delaunay_triangulation_3::dual)
        .def("dual", &dual<kernel,Delaunay_triangulation_3,Facet>,dual_doc)
        .def("dual", &dual_2<kernel,Delaunay_triangulation_3,Cell_handle>)
        .def("is_valid", (bool (Delaunay_triangulation_3::*)(bool, int) const)&Delaunay_triangulation_3::is_valid, is_valid_overloads_0_2())
        .def("is_valid", (bool (Delaunay_triangulation_3::*)(Cell_handle, bool, int) const)&Delaunay_triangulation_3::is_valid, is_valid_overloads_1_3(del_is_valid_doc))
	.def("vertices_in_conflict", &py_vertices_in_conflict<Delaunay_triangulation_3,Point_3,Cell_handle>,del_vertices_in_conflict_doc)
	.def("find_conflicts", &py_find_conflicts<Delaunay_triangulation_3,Point_3,Cell_handle>,del_vertices_in_conflict_doc)
    ;
}


void export_Delaunay_triangulation_3()
{
	Py_Delaunay_triangulation_3<K>();
}
